package elements;

import java.awt.Color;
import java.awt.Graphics;
import java.security.SecureRandom;

import mover.GameMover;
import mover.SimpleMover;
import scaler.Scaler;

public abstract class GameElement implements Cloneable {
	public static final GameMover NO_MOVEMENT = new SimpleMover(0, 0);

	public static final Color DEFAULT_COLOR = Color.BLACK;
	public static final float NOT_VISIBLE = Float.MIN_VALUE;
	private static final Color COLORS[] = new Color[] {
		Color.RED, Color.BLUE, new Color(0xDCC200) /*Yellow*/, Color.BLACK, Color.GREEN,
		Color.CYAN, Color.MAGENTA, Color.ORANGE, Color.PINK
	};

	/** Controls the movement of the Element */
	protected GameMover mover;
	/** Controls the size of the Element */
	protected Scaler scaler;
	/** The color of the Element */
	protected Color color;
	protected float trans = 1.0f, minFade = 0.05f;
	/** The Random Element */
	protected static SecureRandom random = new SecureRandom();

	/** The position of the Element */
	private int x = 10, y = 10;
	private int counter = 1;
	private boolean fadeOut = false;

	public GameElement(GameMover mover, Scaler scaler) {
		this.mover = mover;
		this.scaler = scaler;
		this.color = DEFAULT_COLOR;
	}

	/**
	 * updates the element. Possible is movement, changing text or something similar
	 */
	public void update() {
		// Does the movement
		if(mover != NO_MOVEMENT)
			mover.move(counter);
		counting();
	}

	/**
	 * Increments the counter and resets it, if necessary
	 */
	private void counting() {
		if(counter > 1000000) counter = 1;
		counter++;
	}

	/**
	 * Resets changing attributes of the element but not the look 
	 */
	public void reset() {
		this.counter = 1;
		this.mover.reset();
	}

	/**
	 * Paints the element on the given graphic
	 * @param g the graphic
	 */
	public abstract void paint(Graphics g);

	public abstract int getWidth();
	public abstract int getHeight();

	//Getter and Setter	
	public int getScaledWidth() { return this.scaler.calcX(this.getWidth()); }
	public int getScaledHeight() { return this.scaler.calcY(this.getHeight()); }

	public void setX(int x) { this.x = x; }
	public void addX(int x) { this.x += x; }
	public int getX() { return this.x; }
	public int getUnscaledMovedX() { return this.x + mover.getXPos(); }
	public int getMovedX() { return scaler.calcX(this.x + mover.getXPos());	}

	public void setY(int y) { this.y = y; }
	public void addY(int y) { this.y += y; }
	public int getY() {	return this.y; }
	public int getUnscaledMovedY() { return this.y + mover.getYPos(); }
	public int getMovedY() { return scaler.calcY(this.y + mover.getYPos());	}

	public void setXY(int x, int y){
		this.x = x;
		this.y = y;
	}

	public void setRandomPosition(int width, int height) {
		this.x = 10 + random.nextInt(width-this.getWidth()-20);
		this.y = 10 + random.nextInt(height-this.getHeight()-20);
	}

	/**
	 * Will increase the movement speed of the element,
	 * but will only affect elements which have a x- and yMove of 1.
	 * 
	 * @param speed
	 */
	public void setSpeed(int speed) {
		if(mover == NO_MOVEMENT) return;
		mover.setXMult(speed);
		mover.setYMult(speed);
	}

	public int getCount() { return counter; }

	public GameMover getMover(){return mover;}
	public void setMover(GameMover gm){this.mover = gm;}

	public Scaler getScaler() {
		return this.scaler;
	}

	public void bounce(boolean xAxis, int overlay) {
		if(mover == NO_MOVEMENT) return;

		mover.bounce(xAxis, overlay);
	}

	public void fadeOut(boolean fadeOut) {
		this.fadeOut = fadeOut;
	}

	public boolean shouldFadeOut() {
		return this.fadeOut;
	}

	//COLOR

	public void setMinimalFade(float minFade) {
		this.minFade = minFade;
	}
	
	public float getTransparency() {
		return this.trans;
	}
	
	public void setTransparency(float trans) {
		if(trans<minFade || trans>1.0f) return;
		if(trans == 0) trans = NOT_VISIBLE;
		this.trans = trans;
	}

	public void setColor(Color c) { this.color = c; }

	public Color getTrueRandomColor() {
		return new Color(random.nextInt(0xFFFFFF));
	}

	public Color getRandomColor() {
		return COLORS[random.nextInt(COLORS.length -1)];
	}

	public void setRandomColor() {
		this.color = getRandomColor();
	}

	protected Color transparentColor() {
		Color ret;

		if(trans != 1.0f) {
			float r = (color.getRed()*1.0f)/0xFFFFFF,
					g = (color.getGreen()*1.0f)/0xFFFFFF,
					b = (color.getBlue()*1.0f)/0xFFFFFF;
			ret = new Color(r, g, b, trans);
		} else {
			ret = this.color;
		}

		return ret;
	}

	//CLONE

	@Override
	public abstract GameElement clone() throws CloneNotSupportedException;

	protected void clone_help(GameElement clone) {
		clone.color = this.color;
		clone.counter = this.counter;
		clone.trans = this.trans;
		clone.x = this.x;
		clone.y = this.y;
	}
}
